﻿#define ENABLETIMING

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using BrainTechLLC.ThreadSafeObjects;
using System.Collections;
using System.Collections.ObjectModel;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Globalization;

namespace BrainTechLLC
{
    public static class TryCatchHelper
    {
        public static void Locked(this IObjectLock obj, Action a, Func<bool> test)
        {
            lock (obj.LockObject)
            {
                if (test()) { a(); }
            }
        }

        public static bool AreEqual(this object o1, object o2)
        {
            if (o1 == null && o2 == null)
                return true;

            if ((o1 == null && o2 != null) || (o1 != null && o2 == null))
                return false;

            return o1.Equals(o2);
        }

        public static bool ConvertToBool(this bool? val, bool defaultValue)
        {
            if (val == null)
                return defaultValue;

            return val == true ? true : false;
        }

        public static bool CheckInitialization(this object lockObj, ref bool initialized, Action InitAction)
        {
            if (!initialized)
            {
                lock (lockObj)
                {
                    if (!initialized)
                    {
                        InitAction();
                        initialized = true;
                        return true;
                    }
                }
            }

            return false;
        }
    }

    public static class Extensions
    {
        public static void SetOnAllTypes(this string propertyName, object value, params Type[] types)
        {
            if (types != null)
            {
                foreach (var type in types)
                {
                    PropertyInfo pi = type.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                    if (pi == null)
                    {
                        FieldInfo fi = type.GetField(propertyName, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);

                        if (fi == null)
                        {
                            throw new Exception(string.Format("Property or Member {0} not found on type {1}", propertyName, type.FullName));
                        }

                        fi.SetValue(null, value);
                    }
                    else
                    {
                        pi.SetValue(null, value, null);
                    }
                }
            }
        }

        public static void InvokeOnAllTypes(this string methodName, params Type[] types)
        {
            if (types != null)
            {
                foreach (var type in types)
                {
                    MethodInfo mi = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
                    if (mi == null)
                    {
                        throw new Exception(string.Format("Method {0} not found on type {1}", methodName, type.FullName));
                    }
                    mi.Invoke(null, null);
                }
            }
        }

        public static void WireUpAlsoRaisePropertiesLookup(this Type t, ThreadSafeListAndLookup<string, string> alsoRaisePropertiesLookup)
        {
            var v = from pi in t.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
                    let attribs = pi.ReadAttribute<RaisePropertyChangedForThisPropertyWhenOtherPropertyChangesAttribute>()
                    where attribs != null && attribs.Length > 0
                    select new { PropertyInfo = pi, Attributes = attribs };

            foreach (var attribList in v)
            {
                attribList.Attributes.ForEach(attrib => alsoRaisePropertiesLookup.Add(attrib.Val, attribList.PropertyInfo.Name));
            }
        }

        public static void CheckAlsoRaise(this BaseNotifyPropertyChanged obj, string propertyName, ThreadSafeListAndLookup<string, string> alsoRaisePropertiesLookup)
        {
            if (propertyName != null)
            {
                List<string> also = alsoRaisePropertiesLookup[propertyName];

                if (also.Count > 0)
                {
                    for (int n = 0; n < also.Count; n++)
                    {
                        obj.RaisePropertyChanged(also[n]);
                    }
                }
            }
        }

        public static string GetThumbFileName(this string fileName)
        {
            return fileName + ".thumb";
        }
    }

    public static class AssemblyAndTypes
    {
        /// <summary>
        /// Collects all referenced assemblies that do not start with the "System" or "mscorlib" prefix and are not in the GAC
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static List<Assembly> CollectAssemblies(this Assembly assembly)
        {
            List<Assembly> results = new List<Assembly>();
#if NO_SILVERLIGHT
            if (assembly == null)
                return results;

            AssemblyName[] mods = assembly.GetReferencedAssemblies();

            if (mods != null && mods.Length > 0)
            {
                for (int n = 0; n < mods.Length; n++)
                {
                    var modAssemblyName = mods[n];
                    if (modAssemblyName == null) continue;

                    string modName = modAssemblyName.Name;

                    if (modName.StartsWith("System") || modName.StartsWith("mscorlib"))
                        continue;

                    Assembly asm = Assembly.Load(modAssemblyName);

                    if (asm == null || asm.GlobalAssemblyCache) continue;

                    results.Add(asm);
                    results.AddRange(CollectAssemblies(asm));
                }
            }
#endif
            return results;
        }

        /// <summary>
        /// Crawls out from the current executing assembly and calling assembly and
        /// retrieves all discoverable assembly dependencies
        /// </summary>
        /// <returns></returns>
        public static List<Assembly> GetAllDependentAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
#if NO_SILVERLIGHT
            assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
            assemblies.Add(Assembly.GetEntryAssembly());
#endif
            assemblies.Add(Assembly.GetCallingAssembly());
            assemblies.Add(Assembly.GetExecutingAssembly());
            assemblies.RemoveDuplicates();

            List<Assembly> others = new List<Assembly>();

            assemblies.ForEach(assembly => others.AddRange(assembly.CollectAssemblies()));
            assemblies.AddRange(others);
            assemblies.RemoveDuplicates();

            return assemblies;
        }

        /// <summary>
        /// Returns all types from an assembly that implement/inherit from base type "T"
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"></param>
        /// <returns></returns>
        public static List<Type> TypesThatImplement<T>(this Assembly a) where T : class
        {
            return new List<Type>(
                from type in a.GetTypes()
                where typeof(T).IsAssignableFrom(type)
                select type);
        }
    }

    public static class ConversionAndConditionals
    {
        /// <summary>
        /// Performs specified Action if object is of type t
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="t"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static bool DoIfType<T>(this object o, Type t, Action<T> del) where T : class
        {
            if (typeof(T).IsAssignableFrom(t)) { del(o as T); return true; }
            return false;
        }

        /// <summary>
        /// Performs the specified action on all elements of the array if o is an array type
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static bool ForEachIfArray<T>(this object o, Action<T> del) where T : class
        {
            return o.ForEachIfArray(o.GetType(), del);
        }

        public static bool ForEachIfArray<T>(this object o, Type t, Action<T> del) where T : class
        {
            if (t.IsArray)
            {
                Array a = o as Array;
                foreach (object item in a) { del(item as T); }
                return true;
            }

            return false;
        }

        /// <summary>
        /// If the item of type T2 is null, returns default(T1).  Otherwise returns the result of the specified function.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T1 IfNotNull<T1, T2>(this T2 item, Func<T2, T1> func) where T2 : class
        {
            if (item == null)
                return default(T1);

            return func(item);
        }

        /// <summary>
        /// Determines if the string is a valid long and not equal to long.MinValue
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsLong(this string s)
        {
            return (s.ValueIfLong() != long.MinValue);
        }

        /// <summary>
        /// Retrieves the long value of the string if it's a long, otherwise returns long.MinValue
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static long ValueIfLong(this string s)
        {
            long conversionCheck;
            return (long.TryParse(s, out conversionCheck)) ? conversionCheck : long.MinValue;
        }

        /// <summary>
        /// Formats a string, truncating at maxLen.  If string has length greater than maxLen, optional elipses can be added (via addElipses = true)
        /// </summary>
        /// <param name="s"></param>
        /// <param name="maxLen"></param>
        /// <param name="addElipses"></param>
        /// <returns></returns>
        public static string MaxLength(this string s, int maxLen, bool addElipses)
        {
            if (string.IsNullOrEmpty(s))
                return string.Empty;

            int len = s.Length;

            if (len > maxLen)
            {
                if (addElipses && maxLen > 4)
                    return s.Substring(0, maxLen - 3) + "...";
                else
                    return s.Substring(0, maxLen);
            }

            return s;
        }

        /// <summary>
        /// If the object is null, return null.
        /// Otherwise, perform function del on the object and cast result to type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T WithStringIfNotNull<T>(this object o, Func<object, T> del)
            where T : class
        {
            if (o == null)
                return null;

            return del(o.ToString()) as T;
        }

        /// <summary>
        /// If the object is null, return null.
        /// Otherwise, perform function del on the object's .ToString() value and cast result to type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T WithStringIfNotNull<T>(this object o, Func<string, T> del)
            where T : class
        {
            if (o == null)
                return null;

            return del(o.ToString());
        }
    }

    public static class ListFunctions
    {
        /// <summary>
        /// Returns a new list of items from the original collection that match func(item) == true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="fun"></param>
        /// <returns></returns>
        public static List<T> Take<T>(this List<T> items, Func<T, bool> fun)
        {
            List<T> results = new List<T>();
            for (int n = 0; n < items.Count; n++)
            {
                if (fun(items[n]))
                {
                    results.Add(items[n]);
                }
            }
            return results;
        }

        /// <summary>
        /// Returns a new list of items from the original collection that match func(item) == true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<T> Take<T>(this IEnumerable items, Func<T, bool> func)
        {
            List<T> results = new List<T>();
            foreach (T item in items)
            {
                if (func(item))
                    results.Add(item);
            }
            return results;
        }

#if SILVERLIGHT
#else
        /// <summary>
        /// Performs the specified action on each enum value of the specified enumeration type
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        public static void ForEachEnumValue<T>(this Action<T> action) where T : struct
        {
            Type t = typeof(T);
            var values = Enum.GetValues(t);

            foreach (var o in values)
            {
                action((T)o);
            }
        }
#endif

        /// <summary>
        /// For each attribute in the array, performs the specified action
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="attrs"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T[] ForEachAttribute<T>(this T[] attrs, Action<int, T> action)
        {
            if (attrs != null && attrs.Length > 0)
            {
                for (int n = 0; n < attrs.Length; n++)
                {
                    T attr = attrs[n];
                    action(n, attr);
                }
            }
            return attrs;
        }

        /// <summary>
        /// For each match (defined by match(item) == true), performs the specified action
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="match"></param>
        /// <param name="action"></param>
        public static void ForEachMatch<T>(this IEnumerable<T> items, Func<T, bool> match, Action<T> action)
        {
            foreach (T item in items)
            {
                if (match(item))
                {
                    action(item);
                }
            }
        }

        /// <summary>
        /// For each match (defined by match(item) == true), performs the specified action
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="match"></param>
        /// <param name="action"></param>
        public static void ForEachMatch<T>(this List<T> items, Func<T, bool> match, Action<int, T> action)
        {
            for (int n = 0; n < items.Count; n++)
            {
                T item = items[n];

                if (match(item))
                {
                    action(n, item);
                }
            }
        }

        /// <summary>
        /// performs transformation del(item) on each list item and places the result in
        /// the returned array of T2
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="list"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T2[] PlaceInArray<T1, T2>(this List<T1> list, Func<T1, T2> del) where T1 : class
        {
            T2[] results = new T2[list.Count];

            for (int n = 0; n < list.Count; n++)
            {
                T2 res = del(list[n]);
                results[n] = res;
            }

            return results;
        }

        /// <summary>
        /// Returns a new list containing all matching items as determine by func(item) == true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<T> FindMatching<T>(this List<T> list, Func<T, bool> func) where T : class
        {
            List<T> results = new List<T>();
            for (int n = 0; n < list.Count; n++)
            {
                if (func(list[n]))
                {
                    results.Add(list[n]);
                }
            }
            return results;
        }

        /// <summary>
        /// Goes through the list backwards and performs action on each list item
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static List<T> ForEachBackwards<T>(this List<T> list, Action<int, T> action)
        {
            for (int n = list.Count - 1; n >= 0; n--)
            {
                action(n, list[n]);
            }

            return list;
        }

        /// <summary>
        /// Runs through the list and passes each list item to specific 'func'
        /// If the result of func is not null, sets output parameter item to the found item
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="list"></param>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T2 FindFirst<T1, T2>(this List<T1> list, out T1 item, Func<T1, T2> func)
            where T1 : class
            where T2 : class
        {
            for (int n = 0; n < list.Count; n++)
            {
                T2 found = func(list[n]);

                if (found != null)
                {
                    item = list[n];
                    return found;
                }
            }
            item = null;
            return null;
        }

        /// <summary>
        /// Determines if the string list contains string s, case insensitive
        /// </summary>
        /// <param name="list"></param>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool ContainsIgnoreCase(this List<string> list, string s)
        {
            for (int j = 0; j < list.Count; j++)
            {
                if (list[j].Equals(s, StringComparison.OrdinalIgnoreCase))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Moves "up" the first item that passes the criteria determined by function Match
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="Match"></param>
        /// <returns></returns>
        public static bool MoveUp<T>(this List<T> list, Func<T, bool> Match) where T : class
        {
            T temp = null;
            int n = 1;
            for (; n < list.Count; n++)
            {
                if (Match(list[n]))
                {
                    temp = list[n];
                    list.RemoveAt(n);
                    break;
                }
            }
            if (temp != null)
            {
                list.Insert(n - 1, temp);
            }
            return (temp != null);
        }

        /// <summary>
        /// Moves "down" the first item that passes the criteria determined by function Match
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="Match"></param>
        /// <returns></returns>
        public static bool MoveDown<T>(this List<T> list, Func<T, bool> Match) where T : class
        {
            T temp = null;
            int n = 0;
            for (; n < list.Count - 1; n++)
            {
                if (Match(list[n]))
                {
                    temp = list[n];
                    list.RemoveAt(n);
                    break;
                }
            }

            if (temp != null)
            {
                list.Insert(n + 1, temp);
            }
            return (temp != null);
        }

        /// <summary>
        /// Swaps list item at index n1 with item at index n2
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        public static void Swap<T>(this List<T> list, int n1, int n2) where T : class
        {
            T temp = list[n1];
            list[n1] = list[n2];
            list[n2] = temp;
        }

        /// <summary>
        /// Removes all items from an observable collection that meet criteria test(item) == true, optionally removing only the first found item (find is in reverse order)
        /// Returns true if at least one item was removed, false otherwise
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="onlyFirst"></param>
        /// <param name="test"></param>
        /// <returns></returns>
        public static bool RemoveAll<T>(this ObservableCollection<T> collection, bool onlyFirst, Func<T, bool> test) where T : class
        {
            bool found = false;

            for (int n = collection.Count - 1; n >= 0; n--)
            {
                if (test(collection[n]))
                {
                    found = true;

                    collection.RemoveAt(n);

                    if (onlyFirst)
                        break;
                }
            }

            return found;
        }
        /// <summary>
        /// Removes all items from an observable collection that meet criteria test(item) == true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="test"></param>
        /// <returns></returns>
        public static ObservableCollection<T> RemoveAll<T>(this ObservableCollection<T> list, Func<T, bool> test)
        {
            if (list == null)
                return null;

            for (int n = list.Count - 1; n >= 0; n--)
            {
                if (test(list[n]))
                {
                    list.RemoveAt(n);
                }
            }

            return list;
        }

        /// <summary>
        /// Given a list of items of type TInterface, creates a list of type TClass containing the same items
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static List<TClass> ConvertList<TInterface, TClass>(this List<TInterface> list)
            where TInterface : class
            where TClass : class, TInterface
        {
            List<TClass> returnList = new List<TClass>(list.Count);

            for (int n = 0; n < list.Count; n++)
            {
                returnList.Add(list[n] as TClass);
            }

            return returnList;
        }

        /// <summary>
        /// Given an array of items of type TInterface, creates a list of type TClass containing the same items
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="items"></param>
        /// <returns></returns>
        public static List<TClass> CreateList<TInterface, TClass>(this TInterface[] items)
            where TInterface : class
            where TClass : class, TInterface
        {
            List<TClass> returnList = new List<TClass>(items.Length);

            for (int n = 0; n < items.Length; n++)
            {
                returnList.Add(items[n] as TClass);
            }

            return returnList;
        }

        /// <summary>
        /// Takes a list of items that implement IProvidesUniqueID and finds the max unique ID
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <returns></returns>
        public static long MaxID<T>(this List<T> items)
             where T : class, IProvidesUniqueID
        {
            long max = 0;

            foreach (T item in items)
            {
                if (item.UniqueID > max)
                    max = item.UniqueID;
            }

            return max;
        }

        /// <summary>
        /// takes a list of items of TInterface and casts each to TClass.  Returns an array with the same items but of type TClass
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static TClass[] ToArray<TInterface, TClass>(this List<TInterface> list)
            where TInterface : class
            where TClass : class, TInterface
        {
            TClass[] array = new TClass[list.Count];

            for (int n = 0; n < list.Count; n++)
            {
                array[n] = list[n] as TClass;
            }

            return array;
        }

        /// <summary>
        /// takes an array of items of TInterface and casts each to TClass.  Returns an array with the same items but of type TClass
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="items"></param>
        /// <returns></returns>
        public static TClass[] ToArray<TInterface, TClass>(this TInterface[] items)
            where TInterface : class
            where TClass : class, TInterface
        {
            TClass[] array = new TClass[items.Length];

            for (int n = 0; n < items.Length; n++)
            {
                array[n] = items[n] as TClass;
            }

            return array;
        }

        /// <summary>
        /// takes an array of items of TClass and casts each to TInterface.  Returns an array with the same items but of type TInterface
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="items"></param>
        /// <returns></returns>
        public static TInterface[] ToInterfaceArray<TInterface, TClass>(this TClass[] items)
            where TInterface : class
            where TClass : class, TInterface
        {
            TInterface[] array = new TInterface[items.Length];

            for (int n = 0; n < items.Length; n++)
            {
                array[n] = items[n] as TInterface;
            }

            return array;
        }

        /// <summary>
        /// Compares a new collection with an old collection, using function parameters getKeyT1 and getKeyT2 to determine similarity
        /// Outputs a list of new items (items in new collection that were not in the old collection, and a list of items no longer present in newCollection
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="newCollection"></param>
        /// <param name="oldCollection"></param>
        /// <param name="getKey"></param>
        /// <param name="newItems"></param>
        /// <param name="noLongerPresent"></param>
        /// <returns></returns>
        public static bool CompareCollections<T1>(this IList<T1> newCollection, IList<T1> oldCollection, Func<T1, int> getKey, out List<T1> newItems, out List<T1> noLongerPresent)
        {
            return CompareCollections<T1, T1>(newCollection, oldCollection, getKey, getKey, out newItems, out noLongerPresent);
        }

        /// <summary>
        /// Compares a new collection with an old collection, using function parameters getKeyT1 and getKeyT2 to determine similarity
        /// Outputs a list of new items (items in new collection that were not in the old collection, and a list of items no longer present in newCollection
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="newCollection"></param>
        /// <param name="oldCollection"></param>
        /// <param name="getKeyT1"></param>
        /// <param name="getKeyT2"></param>
        /// <param name="newItems"></param>
        /// <param name="noLongerPresent"></param>
        /// <returns></returns>
        public static bool CompareCollections<T1, T2>(this IList<T1> newCollection, IList<T2> oldCollection, Func<T1, int> getKeyT1, Func<T2, int> getKeyT2, out List<T1> newItems, out List<T2> noLongerPresent)
        {
            List<int> handled = new List<int>();
            newItems = new List<T1>();
            noLongerPresent = new List<T2>();

            foreach (var item1 in newCollection)
            {
                int id1 = getKeyT1(item1);
                bool found = false;

                foreach (var item2 in oldCollection)
                {
                    int id2 = getKeyT2(item2);
                    if (id1 == id2)
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                    newItems.Add(item1);

                handled.Add(id1);
            }

            if (oldCollection != null)
            {
                for (int n = oldCollection.Count - 1; n >= 0; n--)
                {
                    var item2 = oldCollection[n];
                    int id2 = getKeyT2(item2);
                    bool found = false;

                    foreach (var id in handled)
                    {
                        if (id == id2)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                        noLongerPresent.Add(item2);
                }
            }

            return (newItems.Count == 0 && noLongerPresent.Count == 0);
        }

        /// <summary>
        /// Compares a new collection with an old collection, using object.ReferenceEquals to determine object equality
        /// Outputs a list of new items (items in new collection that were not in the old collection, and a list of items no longer present in newCollection        
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="newCollection"></param>
        /// <param name="oldCollection"></param>
        /// <param name="newItems"></param>
        /// <param name="noLongerPresent"></param>
        /// <returns></returns>
        public static bool CompareCollections<T1>(this IList<T1> newCollection, IList<T1> oldCollection, out List<T1> newItems, out List<T1> noLongerPresent)
        {
            List<T1> handled = new List<T1>();
            newItems = new List<T1>();
            noLongerPresent = new List<T1>();

            foreach (var item1 in newCollection)
            {
                bool found = false;

                foreach (var item2 in oldCollection)
                {
                    if (object.ReferenceEquals(item1, item2))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                    newItems.Add(item1);

                handled.Add(item1);
            }

            if (oldCollection != null)
            {
                for (int n = oldCollection.Count - 1; n >= 0; n--)
                {
                    var item2 = oldCollection[n];
                    bool found = false;

                    foreach (var o in handled)
                    {
                        if (object.ReferenceEquals(o, item2))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                        noLongerPresent.Add(item2);
                }
            }

            return (newItems.Count == 0 && noLongerPresent.Count == 0);
        }

        /// <summary>
        /// For each item in the enumerable collection, perform the specified action on the item
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> items, Action<T> action)
        {
            foreach (T item in items)
            {
                action(item);
            }

            return items;
        }

        public static int FindIndexOf<T>(this List<T> list, Func<T, bool> test)
        {
            for (int n = 0; n < list.Count; n++)
            {
                if (test(list[n]))
                {
                    return n;
                }
            }

            return -1;
        }

        public static int FindIndexOf<T>(this ObservableCollection<T> list, Func<T, bool> test)
        {
            for (int n = 0; n < list.Count; n++)
            {
                if (test(list[n]))
                {
                    return n;
                }
            }

            return -1;
        }

        /// <summary>
        /// Perform an action on each member of the observable collection, navigating the collection backwards
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static ObservableCollection<T> ForEachBackwards<T>(this ObservableCollection<T> list, Action<T> action)
        {
            for (int n = list.Count - 1; n >= 0; n--)
            {
                action(list[n]);
            }

            return list;
        }

        public static IEnumerable<T> ForEachIfNotNull<T>(this IEnumerable<T> items, Action<T> action)
        {
            if (items == null)
                return null;

            foreach (T item in items)
                action(item);

            return items;
        }

        /// <summary>
        /// If items is null, returns default(T)
        /// If first item of the list is not a list, return the first item in the list (cast to type T)
        /// If first item of the list is a list of type T, return the first item of the items[0] inner list 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <returns></returns>
        public static T Grab<T>(this IList items)
        {
            if (items == null)
                return default(T);

            IList<T> inner = items[0] as IList<T>;

            if (inner == null)
                return (T)items[0];

            return inner[0];
        }

        /// <summary>
        /// Removes all duplicate items (equality determined using ==)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        public static void RemoveDuplicates<T>(this List<T> items)
             where T : class
        {
            for (int n = 0; n < items.Count; n++)
            {
                for (int j = items.Count - 1; j > n; j--)
                {
                    if (items[n] == items[j])
                    {
                        items.RemoveAt(j);
                    }
                }
            }
        }

        public static void RemoveDuplicates<T>(this List<T> items, Func<T, T, bool> equality)
             where T : class
        {
            for (int n = 0; n < items.Count; n++)
            {
                for (int j = items.Count - 1; j > n; j--)
                {
                    if (equality(items[n], items[j]))
                    {
                        items.RemoveAt(j);
                    }
                }
            }
        }

        /// <summary>
        /// Determines if item is in the set of items (equality determined using the object.Equals(object) method)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="setOfItems"></param>
        /// <returns></returns>
        public static bool IsInSet<T>(this T item, params T[] setOfItems)
        {
            for (int n = 0; n < setOfItems.Length; n++)
            {
                if (item.Equals(setOfItems[n]))
                    return true;
            }
            return false;
        }

    }

    public static class LockingFunctions
    {
        public static void EnterMonitor(this object o, int ms)
        {
            while (!Monitor.TryEnter(o, ms))
            {
                Console.WriteLine("Sleeping 20ms");
                Thread.Sleep(20);
            }
        }
    }

    public static class OutputExtensions
    {
        /// <summary>
        /// If s does not end with a backslash, adds it on, otherwise returns the original string
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string AddBackslashIfNecessary(this string s)
        {
            if (!s.EndsWith("\\"))
                return s + "\\";

            return s;
        }

        /// <summary>
        /// Builds a list from the list items, using comma as the delimiter and function del to format each item
        /// Does not include null list items
        /// This version takes a StringBuilder parameter so that a new one doesn't have to be created
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="sbReused"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static string BuildList<T>(this List<T> items, StringBuilder sbReused, Func<T, string> del)
        {
            return items.BuildList(sbReused, ", ", del);
        }

        /// Builds a list from the enumerable items, using comma as the delimiter and function del to format each item
        /// Does not include null list items
        public static string BuildList<T>(this List<T> items, Func<T, string> del)
        {
            if (items == null)
            {
                return string.Empty;
            }

            StringBuilder sb = new StringBuilder();
            return items.BuildList(sb, del);
        }

        /// <summary>
        /// Builds a list from the enumerable items, using comma as the delimiter and function del to format each item
        /// Does not include null list items
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static string BuildList<T>(this IEnumerable<T> items, Func<T, string> del) where T : class
        {
            return items.BuildList(", ", del);
        }

        /// <summary>
        /// Builds a list from the enumerable items, using parameter 'delimiter' as the delimiter and function del to format each item
        /// Does not include null list items
        /// This version takes a StringBuilder parameter so that a new one doesn't have to be created
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="sbReused"></param>
        /// <param name="delimiter"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static string BuildList<T>(this List<T> items, StringBuilder sbReused, string delimiter, Func<T, string> del)
        {
            sbReused.Length = 0;
            int count = 0;
            if (items == null) return string.Empty;

            for (int n = 0; n < items.Count; n++)
            {
                if (items[n] == null)
                {
                    continue;
                }

                if (count > 0)
                {
                    sbReused.Append(delimiter);
                }

                string s = del(items[n]);

                if (!string.IsNullOrEmpty(s)) { sbReused.Append(s); count++; }
            }
            return sbReused.ToString();
        }

        /// <summary>
        /// Builds a list from the enumerable items, using parameter 'delimiter' as the delimiter and function del to format each item
        /// Does not include null list items
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="delimiter"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static string BuildList<T>(this IEnumerable<T> items, string delimiter, Func<T, string> del)
        {
            if (items == null) return string.Empty;
            StringBuilder sb = new StringBuilder(1024);
            int n = 0;

            foreach (T item in items)
            {
                if (item == null)
                {
                    continue;
                }

                if (n > 0)
                {
                    sb.Append(delimiter);
                }

                string s = del(item);

                if (!string.IsNullOrEmpty(s)) { sb.Append(s); n++; }
            }
            return sb.ToString();
        }
    }

    public static class ReflectionHelpers
    {
        /// <summary>
        /// If methodInfo is null, return null
        /// Otherwise, invoke it using this = thisObject with parameters 'parameters'
        /// Return the return value of the method, converted to a boolean
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <param name="thisObject"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static bool? BoolInvokeIfNotNull(this MethodInfo methodInfo, object thisObject, params object[] parameters)
        {
            if (methodInfo == null)
                return null;

            return Convert.ToBoolean(methodInfo.Invoke(thisObject, parameters));
        }

        /// <summary>
        /// If methodInfo is null, return null
        /// Otherwise, invoke it using this = thisObject with parameters 'parameters'
        /// Return the return value of the method
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <param name="thisObject"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object InvokeIfNotNull(this MethodInfo methodInfo, object thisObject, params object[] parameters)
        {
            if (methodInfo == null)
                return null;

            return methodInfo.Invoke(thisObject, parameters);
        }

        /// <summary>
        /// Reads all attributes of type T1 associated with MethodInfo t
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T1[] ReadAttribute<T1>(this MethodInfo methodInfo)
            where T1 : class, IReadableAttribute
        {
            ThreadSafeLookup<Type, object> lookup = Lookups.MethodInfoAttributeLookup.Get(methodInfo);
            Type t1Type = typeof(T1);

            object o;
            if (lookup.TryGetValue(t1Type, out o))
            {
                if (o == null)
                    return null;

                return o as T1[];
            }

            object[] objs = methodInfo.GetCustomAttributes(typeof(T1), true);

            if (objs != null && objs.Length > 0)
            {
                T1[] results = new T1[objs.Length];

                for (int n = 0; n < objs.Length; n++)
                {
                    results[n] = objs[n] as T1;
                }

                lookup.AddOrSet(t1Type, results);
                return results;
            }

            lookup.AddOrSet(t1Type, null);
            return null;
        }

        /// <summary>
        /// Reads all attributes of type T1 associated with PropertyInfo propInfo
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="propInfo"></param>
        /// <returns></returns>
        public static T1[] ReadAttribute<T1>(this PropertyInfo propInfo)
            where T1 : class, IReadableAttribute
        {
            ThreadSafeLookup<Type, object> lookup = Lookups.PropInfoAttributeLookup.Get(propInfo);
            Type t1Type = typeof(T1);

            object o;
            if (lookup.TryGetValue(t1Type, out o))
            {
                if (o == null)
                    return null;

                return o as T1[];
            }

            object[] objs = propInfo.GetCustomAttributes(typeof(T1), true);
            if (objs != null && objs.Length > 0)
            {
                T1[] results = new T1[objs.Length];

                for (int n = 0; n < objs.Length; n++)
                    results[n] = objs[n] as T1;

                lookup.AddOrSet(t1Type, results);
                return results;
            }

            lookup.AddOrSet(t1Type, null);
            return null;
        }

        /// <summary>
        /// Reads all attributes of type T1 associated with class classType
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="classType"></param>
        /// <returns></returns>
        public static T1[] ReadAttribute<T1>(this Type classType)
            where T1 : class, IReadableAttribute
        {
            ThreadSafeLookup<Type, object> lookup = Lookups.ClassInfoAttributeLookup.Get(classType);
            Type t1Type = typeof(T1);

            object o;
            if (lookup.TryGetValue(t1Type, out o))
            {
                if (o == null)
                    return null;

                return o as T1[];
            }

            object[] objs = classType.GetCustomAttributes(typeof(T1), true);
            if (objs != null && objs.Length > 0)
            {
                T1[] results = new T1[objs.Length];

                for (int n = 0; n < objs.Length; n++)
                    results[n] = objs[n] as T1;

                lookup.AddOrSet(t1Type, results);
                return results;
            }

            lookup.AddOrSet(t1Type, null);
            return null;
        }

        /// <summary>
        /// Reads all method infos that have attribute type t
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static List<MethodInfo> ReadMethodInfoWithCustomAttribute<T1>(this Type t)
            where T1 : class, IReadableAttribute
        {
            // TODO: Cache this info?
            List<MethodInfo> results = new List<MethodInfo>();

            // TODO: private, etc?
            MethodInfo[] methods = t.GetMethods();
            foreach (MethodInfo method in methods)
            {
                T1[] attributes = method.ReadAttribute<T1>();

                if (attributes != null && attributes.Length > 0)
                {
                    results.Add(method);
                }
            }

            return results;
        }

        /// <summary>
        /// Reads all property infos that have attribute type t
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static List<PropertyInfo> ReadPropertyInfoWithCustomAttribute<T1>(this Type t)
            where T1 : class, IReadableAttribute
        {
            List<PropertyInfo> results = new List<PropertyInfo>();

            PropertyInfo[] props = t.GetProperties();
            foreach (PropertyInfo prop in props)
            {
                T1[] attributes = prop.ReadAttribute<T1>();

                if (attributes != null && attributes.Length > 0)
                {
                    results.Add(prop);
                }
            }

            return results;
        }

        /// <summary>
        /// Reads the attribute of type T1 on type t.  Returns its value as type T2
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T2 ReadPropertyValue<T1, T2>(this Type t)
            where T1 : IReadableAttribute
        {
            object[] objs = t.GetCustomAttributes(typeof(T1), true);

            if (objs != null && objs.Length > 0)
            {
                T1 attr = (T1)objs[0];
                return (T2)attr.Value;
            }
            else { return default(T2); }
        }

#if NO_SILVERLIGHT
#if TYPE_ID_PROPERTY_MAP

        internal static readonly ThreadSafeLookup<Type, PropertyDescriptor> _typeIDPropertyMap = new ThreadSafeLookup<Type, PropertyDescriptor>();

        public static PropertyDescriptor IDProperty(this Type type)
        {
            string propName; PropertyDescriptor prop;
            if (_typeIDPropertyMap.TryGetValue(type, out prop)) { return prop; }
            propName = type.ReadPropertyValue<IDProperty, string>();
            prop = TypeDescriptor.GetProperties(type)[propName];
            _typeIDPropertyMap.AddOrSet(type, prop);
            return prop;
        }

#endif
#endif

        /// <summary>
        /// Finds the empty constructor in the collection, or returns null if no constructors take 0 arguments
        /// </summary>
        /// <param name="constructors"></param>
        /// <returns></returns>
        public static ConstructorInfo FindEmptyConstructor(this IEnumerable<ConstructorInfo> constructors)
        {
            foreach (var c in constructors)
            {
                var param = c.GetParameters();

                if (param == null || param.Length == 0)
                    return c;
            }

            return null;
        }

        /// <summary>
        /// Makes a copy of obj at a given depth.  Not bulletproof - just take 1
        /// obj type must have a default constructor (no args) OR must be an array type
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="depth"></param>
        /// <param name="currentDepth"></param>
        /// <returns></returns>
        public static object MakeCopy(this object obj, int depth, int currentDepth)
        {
            Type typeOrig = obj.GetType();
            object newObject = null;

            try
            {
                var constructors = typeOrig.GetConstructors();
                var emptyConstructor = constructors.FindEmptyConstructor();

                if (emptyConstructor != null)
                {
                    newObject = Activator.CreateInstance(typeOrig, null);
                }
                else
                {
                    if (typeOrig.IsArray)
                    {
                        int arrayRank = typeOrig.GetArrayRank();

                        if (arrayRank > 0)
                        {
                            object[] ranks = new object[arrayRank];
                            Type[] types = new Type[arrayRank];
                            Array a = obj as Array;

                            for (int n = 0; n < arrayRank; n++)
                            {
                                int rank = a.GetUpperBound(n);
                                ranks[n] = rank + 1;
                                types[n] = typeof(int);
                            }

                            var c = typeOrig.GetConstructor(types);
                            newObject = c.Invoke(ranks);

                            Array aCopy = newObject as Array;
                            Array.Copy(a, aCopy, a.Length);
                        }
                        else
                        {
                            Console.WriteLine("Unhandled " + typeOrig.Name);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Unhandled " + typeOrig.Name);
                    }
                }

                if (newObject == null)
                    return null;

                var props = obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);

                foreach (var prop in props)
                {
                    if (!prop.CanRead || !prop.CanWrite)
                    {
                        continue;
                    }

                    object oSource = prop.GetValue(obj, null);

                    if (oSource != null)
                    {
                        Type oSourceType = oSource.GetType();
                        object oCopiedValue = oSource;

                        if (currentDepth < depth && oSourceType.IsClass)
                        {
                            oCopiedValue = MakeCopy(oSource, depth, currentDepth + 1);

                            if (oCopiedValue == null)
                                oCopiedValue = oSource;
                        }

                        prop.SetValue(newObject, oCopiedValue, null);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
                Console.WriteLine(ex.ToString());
            }

            return newObject;
        }

        /// <summary>
        /// Gets the value of a property on object 'obj'.  If value of property is null or 0, find a method marked with the attribute [PopulatesProperty("PropertyName")] 
        /// (This method must return an object of type T2)
        /// Run the method and set the property value to the result.
        /// Returns the (possibly newly populated) value of propertyName
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static T2 GetValue<T, T2>(this T obj, string propertyName) where T : class
        {

            PropertyInfo pi = typeof(T).GetProperty(propertyName);
            return obj.GetValue<T, T2>(pi, propertyName);
        }

        public static T2 GetValue<T, T2>(this T obj, PropertyInfo pi) where T : class
        {
            return obj.GetValue<T, T2>(pi, pi.Name);
        }

        public static T2 GetValue<T, T2>(this T obj, PropertyInfo pi, string propertyName) where T : class
        {
            T2 result = (T2)pi.GetValue(obj, null);

            if (default(T2).Equals(result))
            {
                MethodInfo[] mis = typeof(T).GetMethods();
                foreach (MethodInfo mi in mis)
                {
                    object[] objs = mi.GetCustomAttributes(typeof(PopulatesProperty), true);
                    if (objs != null && objs.Length > 0)
                    {
                        PopulatesProperty pp = (PopulatesProperty)objs[0];
                        if (pp.PopulatesPropertyName.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
                        {
                            object ret = mi.Invoke(obj, null);
                            pi.SetValue(obj, (T2)ret, null);
                            return (T2)ret;
                        }
                    }
                }
            }

            return result;
        }
    }

    public static class Threading
    {
        public static Thread CreateAndRunThread(this ThreadStart ts)
        {
            Thread t = CreateThread(ts);
            t.Start();
            return t;
        }

        public static Thread CreateAndRunThread(this ThreadStart ts, bool isBackground)
        {
            Thread t = CreateThread(ts);
            t.IsBackground = isBackground;
            t.Start();
            return t;
        }

        public static Thread CreateAndRunThread(this ParameterizedThreadStart ts, object o)
        {
            Thread t = CreateThread(ts);
            t.Start(o);
            return t;
        }

        public static Thread CreateAndRunThread(this ParameterizedThreadStart ts, bool isBackground, object o)
        {
            Thread t = CreateThread(ts);
            t.IsBackground = isBackground;
            t.Start(o);
            return t;
        }


#if SILVERLIGHT
        public static Thread CreateThread(this ThreadStart ts)
        {
            Thread t = new Thread(ts);
            return t;            
        }

#else
        public static Thread CreateThread(this ThreadStart ts)
        {
            return ts.CreateThread(true, ThreadPriority.Normal, ApartmentState.MTA);
        }
        public static Thread CreateThread(this ParameterizedThreadStart ts)
        {
            return ts.CreateThread(true, ThreadPriority.Normal, ApartmentState.MTA);
        }

        public static Thread CreateThread(this ParameterizedThreadStart ts, bool isBackground, ThreadPriority priority, ApartmentState apartmentState)
        {
            Thread t = new Thread(ts);

#if NO_SILVERLIGHT
            t.TrySetApartmentState(apartmentState);
            t.Priority = priority;
#endif

            t.IsBackground = isBackground;
            return t;
        }

        public static Thread CreateThread(this ThreadStart ts, bool isBackground, ThreadPriority priority, ApartmentState apartmentState)
        {
            Thread t = new Thread(ts);

#if NO_SILVERLIGHT
            t.TrySetApartmentState(apartmentState);
            t.Priority = priority;
#endif

            t.IsBackground = isBackground;
            return t;
        }
#endif
    }

    public static class Serialization
    {
        #region Methods

        /// <summary>
        /// Deserializes an object from a memory stream using binary serialization
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        public static object DeserializeFromBinary(this MemoryStream ms)
        {
            return GetFormatter().Deserialize(ms);
        }

        /// <summary>
        /// Deserializes an object from a memory stream using binary serialization and a specified formatter
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="bf"></param>
        /// <returns></returns>
        public static object DeserializeFromBinary(this MemoryStream ms, IFormatter bf)
        {
            return bf.Deserialize(ms);
        }

        /// <summary>
        /// Deserializes an object from a file stream using binary serialization
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        public static object DeserializeFromBinary(this FileStream ms)
        {
            return GetFormatter().Deserialize(ms);
        }

#if USE_ZIP
        public static byte[] SerializeToZippedBinary(object o)
        {
            byte[] bytes;
            using (MemoryStream ms = new MemoryStream())
            {
                GetFormatter().Serialize(ms, o);
                bytes = ms.ToArray();
            }
            using (MemoryStream ms = new MemoryStream())
            {
                Stream stream = new DeflaterOutputStream(ms,
                new Deflater(Deflater.BEST_COMPRESSION), bytes.Length);
                try
                {
                    stream.Write(bytes, 0, bytes.Length);
                }
                finally
                {
                    stream.Close();
                    stream.Dispose();
                }
                return ms.ToArray();
            }
        }

        public static object DeserializeFromZippedBinary(this byte[] byteData)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                byte[] data = new byte[32000];
                Stream s = new InflaterInputStream(new MemoryStream(byteData));
                try
                {
                    while (true)
                    {
                        int bytes = s.Read(data, 0, 32000);
                        if (bytes < 1) break;
                        ms.Write(data, 0, bytes);
                    }
                }
                finally
                {
                    s.Close();
                    s.Dispose();
                }
                return ms.DeserializeFromBinary();
            }
        }
#endif

        /// <summary>
        /// Deserializes an object from a compressed memory stream
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        public static object DeserializeFromCompressedBinary(this MemoryStream ms)
        {
            using (MemoryStream m = new MemoryStream(ms.GetBuffer().Decompress()))
            {
                m.Seek(0, SeekOrigin.Begin);
                return m.DeserializeFromBinary();
            }
        }

        /// <summary>
        /// Serializes an object from a compressed memory stream and outputs time taken to serialize the object
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static byte[] SerializeToCompressedBinaryWithTiming(this object o)
        {
            byte[] data;
            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    GetFormatter().Serialize(ms, o);
                    watch.Stop();
                    Console.WriteLine(watch.ElapsedMilliseconds);
                }
                catch { throw; }
                data = ms.ToArray();
            }
            return data.Compress();
        }

        /// <summary>
        /// Deserializes an object from a compressed byte array, optionally re-throwing if a serialization exception is thrown or decompression failed
        /// </summary>
        /// <param name="data"></param>
        /// <param name="throwIfException"></param>
        /// <returns></returns>
        public static object DeserializeFromCompressedBinary(this byte[] data, bool throwIfException)
        {
            byte[] decompressed;

            // decompress the data
            try
            {
                decompressed = data.Decompress();
            }
            catch
            {
                if (throwIfException)
                {
                    throw;
                }

                return null;
            }

            return DeserializeFromBinary(decompressed, throwIfException);
        }

        /// <summary>
        /// Deserializes an object from a byte array, optionally re-throwing if a serialization exception is thrown
        /// </summary>
        /// <param name="data"></param>
        /// <param name="throwIfException"></param>
        /// <returns></returns>
        public static object DeserializeFromBinary(this byte[] data, bool throwIfException)
        {
            object o = null;

            using (MemoryStream ms = new MemoryStream(data))
            {
                ms.Seek(0, SeekOrigin.Begin);
                try
                {
                    o = ms.DeserializeFromBinary();
                }
                catch
                {
                    if (throwIfException)
                    {
                        throw;
                    }

                    o = null;
                }
                ms.Close();
            }
            return o;
        }

        /// <summary>
        /// Deserializes an object from a compressed file stream, optionally re-throwing if a serialization exception is thrown or decompression failed
        /// </summary>
        /// <param name="fs"></param>
        /// <returns></returns>
        public static object DeserializeFromCompressedBinary(this FileStream fs, bool throwIfException)
        {
            byte[] data;
            long len = fs.Length;

            using (BinaryReader br = new BinaryReader(fs))
            {
                data = br.ReadBytes(Convert.ToInt32(len));
            }

            return data.DeserializeFromCompressedBinary(throwIfException);
        }

        /// <summary>
        /// Reads a compressed binary serialized file containing an array of object of type T and returns a list of the deserialized objects
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dir"></param>
        /// <returns></returns>
        public static List<T> ReadStorage<T>(this string dir)
            where T : class
        {
            List<T> results = new List<T>();
            string file = typeof(T).Name;

            if (File.Exists(file))
            {
                using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    try
                    {
                        object o = fs.DeserializeFromCompressedBinary(true);
                        sw.Stop();
                        Console.WriteLine(sw.ElapsedMilliseconds);

                        return new List<T>((T[])o);
                    }
                    catch { throw; }
                }
            }

            return results;
        }

        /// <summary>
        /// Save a compressed binary serialized file containing an array of object of type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dir"></param>
        /// <param name="results"></param>
        public static void SaveStorage<T>(this string dir, List<T> results)
            where T : class
        {
            string file = typeof(T).Name;

            T[] arrayResults = results.ToArray();
            byte[] bytes = arrayResults.SerializeToCompressedBinary(true);
            using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.ReadWrite))
            {
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    bw.Write(bytes);
                    bw.Close();
                }
                fs.Close();
            }
        }

        /// <summary>
        /// Serializes an object to a byte array
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static byte[] SerializeToBinary(this object o)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                GetFormatter().Serialize(ms, o);
                return ms.ToArray();
            }
        }

        /// <summary>
        /// Serializes an object to the specified memory stream
        /// </summary>
        /// <param name="o"></param>
        /// <param name="ms"></param>
        public static void SerializeToBinaryMemoryStream(this object o, MemoryStream ms)
        {
            GetFormatter().Serialize(ms, o);
        }

        /// <summary>
        /// Serializes and object to a compressed binary byte array, optionally throwing an exception if an error occurs during serialization or during compression
        /// </summary>
        /// <param name="o"></param>
        /// <param name="throwIfException"></param>
        /// <returns></returns>
        public static byte[] SerializeToCompressedBinary(this object o, bool throwIfException)
        {
            byte[] data;

            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    GetFormatter().Serialize(ms, o);
                }
                catch
                {
                    if (throwIfException)
                    {
                        throw;
                    }
                }

                data = ms.ToArray();
                return data.Compress();
            }
        }

        /// <summary>
        /// Serializes an object, compresses it, and places it in the specified memory stream
        /// </summary>
        /// <param name="o"></param>
        /// <param name="ms"></param>
        /// <param name="throwIfException"></param>
        public static void SerializeToCompressedBinaryMemoryStream(this object o, MemoryStream ms, bool throwIfException)
        {
            byte[] data = o.SerializeToCompressedBinary(throwIfException);
            ms.Write(data, 0, data.Length);
        }

        private static IFormatter GetFormatter()
        {
            //return new NxBinaryFormatter();
            return new BinaryFormatter();
        }

        #endregion Methods
    }

    public static class Populate
    {
        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T())
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T CreateIfNull<T>(ref T item) where T : class, new()
        {
            if (item == null) { Interlocked.CompareExchange<T>(ref item, new T(), null); }
            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T CreateIfNull<T>(ref T item, T value) where T : class
        {
            if (item == null) { Interlocked.CompareExchange<T>(ref item, value, null); }
            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new TClass())
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static TInterface CreateIfNull<TInterface, TClass>(ref TInterface item)
            where TInterface : class
            where TClass : class, TInterface, new()
        {
            if (item == null) { Interlocked.CompareExchange<TInterface>(ref item, new TClass(), null); }
            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T())
        /// Returns item
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T OnDemand<T>(ref T item) where T : class, new()
        {
            if (item == null)
            {
                Interlocked.CompareExchange<T>(ref item, new T(), null);
            }

            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (return value from func())
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T OnDemand<T>(ref T item, Func<T> func) where T : class
        {
            if (item == null)
            {
                Interlocked.CompareExchange<T>(ref item, func(), null);
            }

            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (return value from func())
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T1 OnDemand<T1, T2>(ref T1 item, Func<T2> func)
            where T1 : class
            where T2 : class
        {
            if (item == null)
                Interlocked.CompareExchange<T1>(ref item, func() as T1, null);

            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T2() as T1)
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T1 OnDemand<T1, T2>(ref T1 item)
            where T1 : class
            where T2 : class, new()
        {
            if (item == null)
                Interlocked.CompareExchange<T1>(ref item, new T2() as T1, null);

            return item;
        }

        /// <summary>
        /// If value.Equals(varToCheck) then assign varToCheck the result of del()
        /// returns varToCheck
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="value"></param>
        /// <param name="varToCheck"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T1 PopulateIf<T1>(this T1 value, ref T1 varToCheck, Func<T1> del)
        {
            if (value.Equals(varToCheck))
            {
                varToCheck = del();
            }

            return varToCheck;
        }
    }

    public static partial class Lookups
    {
        public static readonly ThreadSafeLookupOnDemand<Type, ThreadSafeLookup<Type, object>> ClassInfoAttributeLookup = new ThreadSafeLookupOnDemand<Type, ThreadSafeLookup<Type, object>>();
        public static readonly ThreadSafeLookupOnDemand<string, ThreadSafeCounter> CounterLookup = new ThreadSafeLookupOnDemand<string, ThreadSafeCounter>();
        public static readonly ThreadSafeLookupOnDemand<string, object> LockableLookup = new ThreadSafeLookupOnDemand<string, object>();
        public static readonly ThreadSafeLookupOnDemand<MethodInfo, ThreadSafeLookup<Type, object>> MethodInfoAttributeLookup = new ThreadSafeLookupOnDemand<MethodInfo, ThreadSafeLookup<Type, object>>();
        public static readonly ThreadSafeLookupOnDemand<PropertyInfo, ThreadSafeLookup<Type, object>> PropInfoAttributeLookup = new ThreadSafeLookupOnDemand<PropertyInfo, ThreadSafeLookup<Type, object>>();

        public static ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo> ElseLookup = new ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo>();
        public static ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo> GeneralLookup = new ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo>();
        public static ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo> IfLookup = new ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo>();
        public static ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo> ThenLookup = new ThreadSafeLookupOnDemandWithDelegate<string, MethodInfo>();

        internal static readonly ThreadSafeLookup<Type, PropertyDescriptor> _typeIDPropertyMap = new ThreadSafeLookup<Type, PropertyDescriptor>();
    }

    public static partial class Timing
    {
#if SILVERLIGHT
#else
        public static readonly ThreadSafeLookup<int, Stopwatch> Stopwatches = new ThreadSafeLookup<int, Stopwatch>();
        public static long NanoSecondsPerTick = 0;
        public static object _lockObject = new object();

        /// <summary>
        /// Begins timing code execution on the current thread
        /// </summary>
        [Conditional("ENABLETIMING")]
        public static void BeginTiming()
        {
            Stopwatch sw = GetStopwatch();
            sw.Reset();
            sw.Start();
        }

        /// <summary>
        /// Ends timing code execution on the current thread, executing action(double) with the time elapsed as its parameter
        /// </summary>
        /// <param name="a"></param>
        [Conditional("ENABLETIMING")]
        public static void EndTiming(Action<double> a)
        {
            double d = EndTiming();
            a(d);
        }

        [Conditional("ENABLETIMING")]
        public static void EndTiming(string a)
        {
            double d = EndTiming();
            AllStats.GetInstance().AddTime(a, d);
        }

        /// <summary>
        /// Returns the number of nanoseconds per tick
        /// </summary>
        /// <returns></returns>
        public static long GetNanosecondsPerTick()
        {
            if (NanoSecondsPerTick == 0)
            {
                lock (_lockObject)
                {
                    if (NanoSecondsPerTick == 0)
                    {
                        long frequency = Stopwatch.Frequency;
                        NanoSecondsPerTick = (1000L * 1000L * 1000L) / frequency;
                    }
                }
            }

            return NanoSecondsPerTick;
        }

        /// <summary>
        /// End timing on the thread and return the results
        /// </summary>
        /// <returns></returns>
        private static double EndTiming()
        {
            Stopwatch sw = GetStopwatch();
            sw.Stop();

            return Convert.ToDouble(sw.ElapsedTicks * GetNanosecondsPerTick()) / 1000D;
        }

        /// <summary>
        /// Gets a stopwatch specific to the thread that is executing
        /// </summary>
        /// <returns></returns>
        private static Stopwatch GetStopwatch()
        {
            Stopwatch result;
            int key = Thread.CurrentThread.ManagedThreadId;

            if (!Stopwatches.TryGetValue(key, out result) || result == null)
            {
                result = new Stopwatch();
                Stopwatches.Add(key, result);
            }

            return result;
        }
#endif
    }

    public static class MathExt
    {
        public static bool Within(this double d1, double d2, double percent)
        {
            double d1Low = d1 - (d1 * percent);
            double d1High = d1 + (d1 * percent);
            return (d2 < d1High && d2 > d1Low);
        }
    }

    public enum DefaultValue
    {
        None = 0,
        True = 1,
        False = 2
    }

    public static class MiscExtensionMethods
    {
#if SILVERLIGHT
        public static string[] Split(this string orig, char[] delims, int max, StringSplitOptions options)
        {
            string[] strings = orig.Split(delims, options);
            if (strings.Length > max)
            {
                string[] results = new string[max];
                int n = 0;
                for (; n < max - 1; n++)
                {
                    results[n] = strings[n];
                }
                StringBuilder sb = new StringBuilder();
                for (; n < strings.Length - 1; n++)
                {
                    sb.Append(strings[n] + delims[0]);
                }
                sb.Append(strings[n]);
                results[max - 1] = sb.ToString();
                return results;
            }
            else
            {
                return strings;
            }
        }
#endif

        public static bool StripNextWord(this string delimiters, ref string s, out string stringOut)
        {
            if (string.IsNullOrEmpty(s))
            {
                stringOut = null;
                return false;
            }

            string[] strings = s.Split(delimiters.ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);

            if (strings.Length == 0)
            {
                s = string.Empty;
                stringOut = null;
                return false;
            }

            if (strings.Length == 1)
            {
                s = string.Empty;
            }
            else
            {
                s = strings[1];
            }
            stringOut = strings[0];
            return true;
        }

        public static string EmptyIfNull(this string s)
        {
            if (string.IsNullOrEmpty(s))
                return string.Empty;

            return s;
        }

        public static double CreateNumeric(this string value)
        {
            double result;

            if (double.TryParse(
                value,
                NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint |
                NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite |
                NumberStyles.AllowThousands | NumberStyles.AllowTrailingWhite,
                null,
                out result))
            {
                return result;
            }

            if (value.EndsWith("."))
            {
                if (double.TryParse(
                value.Substring(0, value.Length - 1),
                NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint |
                NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite |
                NumberStyles.AllowThousands | NumberStyles.AllowTrailingWhite,
                null,
                out result))
                {
                    return result;
                }
            }

            return double.NegativeInfinity;
        }

        public static bool ReturnBoolean(this object o, DefaultValue defaultValue)
        {
            if (o == null)
                return (defaultValue == DefaultValue.True);

            return Convert.ToBoolean(o);
        }

        public static bool AddNonDuplicateLine(this StringBuilder sb, string line)
        {
            if (sb.ToString().IndexOf(line) < 0)
            {
                sb.AppendLine(line);
                return true;
            }

            return false;
        }

        public static bool StartsWith(this string item, params string[] setToCheck)
        {
            foreach (string check in setToCheck)
            {
                if (item.StartsWith(check))
                    return true;
            }

            return false;
        }

        public static bool IsIn<T>(this T item, params T[] setToCheck)
        {
            foreach (T check in setToCheck)
            {
                if (item.Equals(check))
                    return true;
            }

            return false;
        }

        public static T2 TryGetValueOrNull<T1, T2>(this Dictionary<T1, T2> dictionary, T1 key) where T2 : class
        {
            T2 element;

            if (dictionary.TryGetValue(key, out element))
                return element;

            return null;
        }

        public static T2 CheckNull<T1, T2>(this T1 value, T2 valueIfNull, Func<T1, T2> valueIfNotNull) where T1 : class
        {
            if (value == null)
                return valueIfNull;

            return valueIfNotNull(value);
        }

        public static void ForEachIndexed<T>(this List<T> list, Action<int, T> action)
        {
            for (int n = 0; n < list.Count; n++)
                action(n, list[n]);
        }

        public static int Sum<T>(this IEnumerable<T> collection, Func<T, int> returnSum)
        {
            int sum = 0;
            foreach (T item in collection)
            {
                sum += returnSum(item);
            }
            return sum;
        }

        //public static void CopyPropertiesTo(this object o1, object o2)
        //{
        //    Type newType = o2.GetType();

        //    var propertiesToCopy = from pi in o1.GetType().GetProperties()
        //                           let propInfo = newType.GetProperty(pi.Name)
        //                           where propInfo != null && propInfo.CanWrite
        //                           select new { sourcePropInfo = pi, destPropInfo = propInfo };

        //    propertiesToCopy.ForEach((v) =>
        //    {
        //        object val = v.sourcePropInfo.GetValue(o1, null);
        //        try
        //        {
        //            v.destPropInfo.SetValue(o2, val, null);
        //        }
        //        catch (Exception ex) { Debug.WriteLine(ex.ToString()); }
        //    });
        //}

        public static Guid ToGuid(this string guid)
        {
            try { return new Guid(guid); }
            catch { }

            return Guid.Empty;
        }

        public static void RaiseEvent(this EventHandler evt, object sender)
        {
            if (evt != null)
            {
                evt(sender, EventArgs.Empty);
            }
        }

        public static void RaiseEvent<T>(this EventHandler<ObjectEventArgs<T>> evt, object sender, T item) where T : class
        {
            if (evt != null)
            {
                evt(sender, new ObjectEventArgs<T>(item));
            }
        }

        public static void RaiseEvent<T1, T2>(this EventHandler<ObjectEventArgs<T1, T2>> evt, object sender, T1 item1, T2 item2)
            where T1 : class
            where T2 : class
        {
            if (evt != null)
            {
                evt(sender, new ObjectEventArgs<T1, T2>(item1, item2));
            }
        }

        public static void RaiseEvent<T1, T2, T3>(this EventHandler<ObjectEventArgs<T1, T2, T3>> evt, object sender, T1 item1, T2 item2, T3 item3)
            where T1 : class
            where T2 : class
            where T3 : class
        {
            if (evt != null)
            {
                evt(sender, new ObjectEventArgs<T1, T2, T3>(item1, item2, item3));
            }
        }

        public static void RaiseEvent<T>(this EventHandler<ObjectEventArgsNonRef<T>> evt, object sender, T item)
        {
            if (evt != null)
            {
                evt(sender, new ObjectEventArgsNonRef<T>(item));
            }
        }

        public static void RaiseEvent<T1, T2>(this EventHandler<ObjectEventArgsNonRef<T1, T2>> evt, object sender, T1 item1, T2 item2)
        {
            if (evt != null)
            {
                evt(sender, new ObjectEventArgsNonRef<T1, T2>(item1, item2));
            }
        }

        public static void RaiseEvent(this PropertyChangedEventHandler evt, object sender, string propName)
        {
            if (evt != null)
            {
                evt(sender, new PropertyChangedEventArgs(propName));
            }
        }

        public static ObservableCollection<T> ToObservable<T>(this IEnumerable<T> items)
        {
            ObservableCollection<T> results = new ObservableCollection<T>();
            items.ForEach(o => results.Add(o));
            return results;
        }
    }
}
